package com.woniu.his.sms.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.woniu.his.exception.HisException;
import com.woniu.his.sms.infra.model.*;
import com.woniu.his.sms.infra.mapper.SkdMapper;
import com.woniu.his.sms.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.woniu.his.sms.service.dto.*;
import com.woniu.his.sms.service.param.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * sms_skd(排班)表 服务实现类
 * </p>
 *
 * @author cb
 * @since 2022-11-25
 */
@Service
@Slf4j
public class SkdServiceImpl extends ServiceImpl<SkdMapper, Skd> implements SkdService {


    @Resource
    private StaffService smsStaffService;


    @Resource
    private SkdService skdService;

    @Resource
    private RegistrationRankService registrationRankService;

    @Resource
    private DeptService deptService;


    /**
     * 新增排班规则规则
     *
     * @param param
     * @return
     */
    @Resource
    private SkdRuleItemService skdRuleItemService;

    @Resource
    private SkdRuleService skdRuleService;


    @Resource
    private StaffService staffService;


    /**
     * 创建一个排班规则和项目
     *
     * @param param
     * @return
     */
    @Override
    public boolean createRule(SkdRuleServerParam param) {


        Dept byId = deptService.getById(param.getDeptId());
        if (byId == null || byId.getDeptStatus().equals("OFF")) throw new HisException("科室不存在或者状态不可以使用", 2001);

        //排班规则表
        SkdRule skdRule = new SkdRule();
        skdRule.setRuleStatus("ON");
        skdRule.setOperatorId(param.getOperatorId());
        skdRule.setOperateTime(DateUtil.date());
        skdRule.setRuleName(param.getRuleName());
        skdRule.setDescription(param.getDescription());
        skdRule.setDeptId(param.getDeptId());
        boolean save = skdRuleService.save(skdRule);
        //排班规则项目表
        List<SkdRuleItemServiceParam> list = param.getSmsSkdRuleItemParamList();
        for (SkdRuleItemServiceParam params : list) {
            Staff byId1 = staffService.getById(params.getStaffId());
            if (byId1 == null) continue;
            SkdRuleItem skdRuleItem = new SkdRuleItem();
            skdRuleItem.setStaffId(params.getStaffId());
            skdRuleItem.setDaysOfWeek(params.getDaysOfWeek());
            skdRuleItem.setItemStatus("ON");
            skdRuleItem.setSkLimit(params.getSkLimit());
            skdRuleItem.setSkRuleId(skdRule.getId());
            skdRuleItemService.save(skdRuleItem);
        }
        return save;
    }

    /**
     * 删除排班规则和项目
     *
     * @param ids
     * @return
     */
    @Override
    public boolean deleteRule(List<Long> ids) {
        //先找出所有的规则
        List<SkdRule> skdRules = skdRuleService.listByIds(ids);
        for (SkdRule skdRule : skdRules) {
            skdRule.setRuleStatus("OFF");
        }
        boolean b = skdRuleService.updateBatchById(skdRules);
        //通过规则id找到规则项目
        List<SkdRuleItem> skdRuleItems = skdRuleItemService.list(new QueryWrapper<SkdRuleItem>().in("sk_rule_id", ids));
        for (SkdRuleItem skdRuleItem : skdRuleItems) {
            skdRuleItem.setItemStatus("OFF");
        }
        boolean b1 = skdRuleItemService.updateBatchById(skdRuleItems);
        return b && b1;
    }

    /**
     * 更新 排班工作项目
     *
     * @param param
     * @return
     */
    @Override
    public boolean updateRule(SkdRuleServerParam param) {
        //先根据id查找
        SkdRule byId = skdRuleService.getById(param.getId());
        byId.setOperatorId(param.getOperatorId());
        byId.setOperateTime(DateUtil.date());
        byId.setRuleName(param.getRuleName());
        byId.setDescription(param.getDescription());
        byId.setDeptId(param.getDeptId());
        boolean b = skdRuleService.updateById(byId);
        //再修改项目
        List<SkdRuleItemServiceParam> smsSkdRuleItemParamList = param.getSmsSkdRuleItemParamList();
        List<SkdRuleItem> skdRuleItems = skdRuleItemService.list(new QueryWrapper<SkdRuleItem>().eq("sk_rule_id", byId.getId()));
        for (SkdRuleItemServiceParam params : smsSkdRuleItemParamList) {
            for (SkdRuleItem skdRuleItem : skdRuleItems) {
                if (skdRuleItem.getId() == params.getId()) {
                    skdRuleItem.setSkLimit(params.getSkLimit());
                    skdRuleItem.setDaysOfWeek(params.getDaysOfWeek());
                    skdRuleItem.setStaffId(params.getStaffId());
                }
            }
        }
        boolean b1 = skdRuleItemService.updateBatchById(skdRuleItems);

        return b && b1;
    }

    /**
     * 根据规则id查询
     *
     * @param sdkRuleId
     * @return
     */
    @Override
    public SkuRuleServiceDto queryRuleDetail(Long sdkRuleId) {
        QueryWrapper<SkdRule> skdRuleQueryWrapper = new QueryWrapper<>();
        skdRuleQueryWrapper.eq("id", sdkRuleId);
        skdRuleQueryWrapper.eq("rule_status", "ON");
        SkdRule one = skdRuleService.getOne(skdRuleQueryWrapper);
        List<SkdRuleItem> sk_rule_id = skdRuleItemService.list(new QueryWrapper<SkdRuleItem>().eq("sk_rule_id", sdkRuleId));
        if (one == null) return null;
        SkuRuleServiceDto dto = BeanUtil.copyProperties(one, SkuRuleServiceDto.class);
        dto.setRuleItems(BeanUtil.copyToList(sk_rule_id,SmsSkdRuleItemDto.class));
        return dto;
    }

    /**
     * 根据部门id查询排班规则信息分页
     *
     * @param params
     * @return
     */
    @Override
    public SkdRulePageDto queryPageRule(SkdRulePageServiceParam params) {
        QueryWrapper<SkdRule> wrapper = new QueryWrapper<>();
        if (params.getDeptId() != null) wrapper.eq("dept_id", params.getDeptId());
        Page<SkdRule> page = skdRuleService.page(new Page<SkdRule>(params.getIndexPage(), params.getPageSize()), wrapper);
        List<SkuRuleServiceDto> skuRuleServiceDtos = BeanUtil.copyToList(page.getRecords(), SkuRuleServiceDto.class);
        for (SkuRuleServiceDto skuRuleServiceDto : skuRuleServiceDtos) {
            List<SkdRuleItem> sk_rule_id = skdRuleItemService.list(new QueryWrapper<SkdRuleItem>().in("sk_rule_id", skuRuleServiceDto.getId()));
            skuRuleServiceDto.setRuleItems(BeanUtil.copyToList(sk_rule_id,SmsSkdRuleItemDto.class));
        }
        SkdRulePageDto dto = new SkdRulePageDto();
        dto.setTotal(page.getTotal());
        dto.setPageSize(page.getCurrent());
        dto.setSkuRulePages(skuRuleServiceDtos);
        return dto;
    }

    /**
     * 分页查询排班记录
     *
     * @param param
     * @return
     */
    @Override
    public SkuSkdPageDto queryPageSkd(SkuSkdPageServiceParam param) {

        QueryWrapper<Skd> wrapper = new QueryWrapper<>();
        //根据科室id查询
        if(param.getDeptId()!=null) wrapper.eq("dept_id",param.getDeptId());
        //根据员工id查询
        if(param.getStaffId()!=null)wrapper.eq("staff_id",param.getStaffId());
        //根据午别查询
        if(param.getNoon()!=null) wrapper.eq("noon",param.getNoon());
        //根据开始时间查询
        if(param.getStartDate()!=null) wrapper.ge("date",param.getStartDate());
        if(param.getEndDate()!=null) wrapper.le("date",param.getEndDate());

        List<Staff> stafflist = new ArrayList<>();
        //根据挂号等级来查询
        if(param.getRegistrationRankId()!=null){
            //先查询出来这个等级的所有医生信息
             stafflist = smsStaffService.list(new QueryWrapper<Staff>().eq("registration_rank_id", param.getRegistrationRankId()));
            List<Long> collect = stafflist.stream().map(Staff::getId).collect(Collectors.toList());
            wrapper.in("staff_id",collect);
        }
        Page<Skd> page = page(new Page<Skd>(param.getIndexPage(), param.getPageSize()), wrapper);
        SkuSkdPageDto skuSkdPageDto = new SkuSkdPageDto();
        skuSkdPageDto.setIndexPage(page.getCurrent());
        skuSkdPageDto.setTotal(page.getTotal());
        List<Skd> records = page.getRecords();
        List<SmsSkdDto> list1 =new ArrayList<>();
        //封装信息
        for (Skd record : records) {
            //封装信息
            Staff byId = smsStaffService.getById(record.getStaffId());
            if(!byId.getStaffStatus().equals("AVAILABLE")) continue;
            SmsSkdDto smsSkdDto = new SmsSkdDto();
            smsSkdDto.setId(record.getId());
            smsSkdDto.setStaffName(byId.getStaffName());
            smsSkdDto.setDate(record.getDate());
            smsSkdDto.setNoon(record.getNoon());
            Dept byId1 = deptService.getById(record.getDeptId());
            smsSkdDto.setDeptName(byId1.getDeptName());
            smsSkdDto.setSkLimit(record.getSkLimit());
            RegistrationRank byId2 = registrationRankService.getById(byId.getRegistrationRankId());
            smsSkdDto.setRegistrationRank(byId2.getRegistrationRankName());
            smsSkdDto.setRemain(record.getRemain());
            list1.add(smsSkdDto);
        }
        skuSkdPageDto.setSkuSkdResulList(list1);
        return skuSkdPageDto;
    }

    /**
     * 不分页查询排班记录
     *
     * @param param
     * @return
     */
    @Override
    public List<SmsSkdDto> querySkd(SkuSkdServiceParam param) {

        QueryWrapper<Skd> wrapper = new QueryWrapper<>();
        //根据科室id查询
        if(param.getDeptId()!=null) wrapper.eq("dept_id",param.getDeptId());
        //根据员工id查询
        if(param.getStaffId()!=null)wrapper.eq("staff_id",param.getStaffId());
        //根据午别查询
        if(param.getNoon()!=null&&!param.getNoon().trim().equals("")) wrapper.eq("noon",param.getNoon());
        //根据开始时间查询
        if(param.getStartDate()!=null) wrapper.ge("date",param.getStartDate());
        if(param.getEndDate()!=null) wrapper.le("date",param.getEndDate());

        List<Staff> stafflist = new ArrayList<>();
        //根据挂号等级来查询
        if(param.getRegistrationRankId()!=null){
            //先查询出来这个等级的所有医生信息
            stafflist = smsStaffService.list(new QueryWrapper<Staff>().eq("registration_rank_id", param.getRegistrationRankId()));
            List<Long> collect = stafflist.stream().map(Staff::getId).collect(Collectors.toList());
            wrapper.in("staff_id",collect);
        }
        List<Skd> list = list(wrapper);
        log.info("排班记录表:{}",list);
        List<SmsSkdDto> list1 =new ArrayList<>();
        for (Skd skd : list) {
            //封装信息
            Staff byId = smsStaffService.getById(skd.getStaffId());
            if(!byId.getStaffStatus().equals("AVAILABLE")) continue;
                SmsSkdDto smsSkdDto = new SmsSkdDto();
                smsSkdDto.setId(skd.getId());
                smsSkdDto.setStaffName(byId.getStaffName());
                smsSkdDto.setDate(skd.getDate());
                smsSkdDto.setNoon(skd.getNoon());
                Dept byId1 = deptService.getById(skd.getDeptId());
                if(byId1==null) continue;
                smsSkdDto.setDeptName(byId1.getDeptName());
                smsSkdDto.setSkLimit(skd.getSkLimit());
                RegistrationRank byId2 = registrationRankService.getById(byId.getRegistrationRankId());
                if(byId2 == null) continue;
                smsSkdDto.setRegistrationRank(byId2.getRegistrationRankName());
                smsSkdDto.setRemain(skd.getRemain());
                list1.add(smsSkdDto);
            }
            return list1;
        }

    @Override
    public List<SmsSkdRuleItemDto> listCanSkdStaff(Long skRuleId) {
        QueryWrapper<SkdRuleItem> wrapper = new QueryWrapper<>();
        wrapper.eq("item_status","ON");
        wrapper.eq("sk_rule_id",skRuleId);
        List<SkdRuleItem> list = skdRuleItemService.list(wrapper);
        if(list.isEmpty()) return null;
        return BeanUtil.copyToList(list,SmsSkdRuleItemDto.class);
    }

    /**
     * 根据多条排班规则 生成排班记录
     *
     * @param createSkdParam
     * @return
     */
    @Override
    public Boolean generateSkd(CreateSkdServiceParam createSkdParam) {
        //如果时间不对就失败
        if(createSkdParam.getEndDate().compareTo(createSkdParam.getStartDate()) < 0){
            return false;
        }
        //先设置排班规则id与科室id对应
        QueryWrapper<SkdRule> wrapper = new QueryWrapper<>();
        wrapper.in("id", createSkdParam.getRuleIds());
        wrapper.eq("rule_status", "ON");
        List<SkdRule> id = skdRuleService.list(wrapper);
        if(id.isEmpty()) return false;
        Map<Long, Long> ruleIdToDeptIdMap = new Hashtable<>();
        for (SkdRule skdRule : id) {
            ruleIdToDeptIdMap.put(skdRule.getId(),skdRule.getDeptId());
        }
        ////调用SmsSkdRuleItemDao查询所有ruleIds的排班项，并合并为一个Map
        QueryWrapper<SkdRuleItem> w = new QueryWrapper<>();
        w.in("sk_rule_id",createSkdParam.getRuleIds());
        w.eq("item_status","ON");
        List<SkdRuleItem> skdRuleItems = skdRuleItemService.list(w);
        if (skdRuleItems.isEmpty())return false;
        Map<Long, List<SkdRuleItem>> deptIdToItemListMap = new Hashtable<>();
        //生成一个StaffIdList
        List<Long> staffIdList = new ArrayList<>();
        for(SkdRuleItem smsSkdRuleItem :skdRuleItems){
            Long currentDeptId = ruleIdToDeptIdMap.get(smsSkdRuleItem.getSkRuleId());
            List<SkdRuleItem> currentItemList;
            if(deptIdToItemListMap.containsKey(currentDeptId)){
                currentItemList = deptIdToItemListMap.get(currentDeptId);
                //判断该staff是否已经存在
                for(SkdRuleItem currentItem : currentItemList){
                    if(smsSkdRuleItem.getStaffId() == currentItem.getStaffId()){
                        return false;
                    }
                }
            }else {
                currentItemList = new ArrayList<>();
            }
            currentItemList.add(smsSkdRuleItem);
            staffIdList.add(smsSkdRuleItem.getStaffId());
            deptIdToItemListMap.put(currentDeptId,currentItemList);
        }
        //没有重复，则遍历排班记录表，根据Date\staffId删除排班记录
        List<Long> collect = skdRuleItems.stream().map(SkdRuleItem::getStaffId).collect(Collectors.toList());
        QueryWrapper<Skd> skdQueryWrapper = new QueryWrapper<>();
        skdQueryWrapper.in("staff_id",collect);
        skdQueryWrapper.ne("skd_status","OFF");
        List<Skd> list = skdService.list(skdQueryWrapper);
        if (!list.isEmpty()) {
            for (Skd skd : list) {
                skd.setSkdStatus("OFF");
            }
            skdService.updateBatchById(list);
        }

        //遍历起止时间,判断每一天为周几，取出所有itemList中的daysOfWeek，如果为周i，则取出第2(i-1)位和第2(i-1)+1位。如果为0，则continue，如果为1，则插入skd
        List<Date> listDate = getDatesBetweenTwoDate(createSkdParam.getStartDate(), createSkdParam.getEndDate());
        for (Date today : listDate) {
            Calendar calendar = Calendar.getInstance();

            // 设置时分秒毫秒为0:0:0
            calendar.set(Calendar.HOUR_OF_DAY, 0);
            calendar.set(Calendar.MINUTE, 0);
            calendar.set(Calendar.SECOND, 0);
            calendar.set(Calendar.MILLISECOND, 0);
            System.out.println(today);
            calendar.setTime(today);

            int week = calendar.get(Calendar.DAY_OF_WEEK) - 2;  //此时week，周日为-1
            if (week == -1) {
                week = 6;       //将周日设置为6
            }

            System.out.println(week);
            //遍历map
            for (Long currentDeptId : deptIdToItemListMap.keySet()) {
                List<SkdRuleItem> currentItemList = deptIdToItemListMap.get(currentDeptId);
                //遍历同一科室id下Item
                for (SkdRuleItem ruleItem : currentItemList) {
                    String noon = ruleItem.getDaysOfWeek();
                    String[] split = noon.split("，");
                    for (int i = 0; i < split.length; i++) {
                        log.info("排班信息:{}", split[i]);
                        if (split[i].equals("星期" + (week + 1) + "上午")) {
                            //添加上午值班信息
                            /**
                             * 时间段 上午MORNING 下午AFTERNOON
                             */
                            log.info("添加上午值班信息:{}",noon);
                            Skd skd = new Skd();
                            skd.setDate(today);
                            skd.setSkdStatus("NOT_ARRIVE");
                            skd.setRemain(ruleItem.getSkLimit());
                            skd.setNoon("MORNING");
                            skd.setStaffId(ruleItem.getStaffId());
                            skd.setDeptId(currentDeptId);
                            skd.setSkLimit(ruleItem.getSkLimit());
                            skdService.save(skd);
                        }
                        if (split[i].equals("星期" + (week + 1) + "下午")) {
                            //添加下午值班信息
                            log.info("添加下午值班信息:{}", noon);
                            Skd skd = new Skd();
                            skd.setDate(today);
                            skd.setSkdStatus("NOT_ARRIVE");
                            skd.setRemain(ruleItem.getSkLimit());
                            skd.setNoon("AFTERNOON");
                            skd.setStaffId(ruleItem.getStaffId());
                            skd.setDeptId(currentDeptId);
                            skd.setSkLimit(ruleItem.getSkLimit());
                            skdService.save(skd);
                        }
                    }
                }
            }
        }
        return true;
    }

    /**
     * 根据起止日期生成日期List
     *
     * @param startDate
     * @param endDate
     * @return
     */
    public List<Date> getDatesBetweenTwoDate(Date startDate, Date endDate) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(startDate);
        List<Date> dateList = new ArrayList<>();
        while (calendar.getTime().compareTo(endDate) <= 0) {
            dateList.add(calendar.getTime());
            calendar.add(Calendar.DATE, 1);

        }
        return dateList;
    }


}
